package lesson03;


import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

/**
 * - Atmic：比Sync效率高，是因为内部用了无锁的操作  【CAS Campare And Set/Swap 】
 * - Sync：有可能向操作系统申请 了重量级锁
 * - LongAdder：线程数特别多的时候有优势， 内部用了分段实现，分段计算汇总结果，线程数少没有优势
 */
public class SyncAtmicLongAdder {

    static Long count1 = 0L;
    static AtomicLong count2 = new AtomicLong(0L);
    static LongAdder count3 = new LongAdder();

    // 循环次数
    static final int len = 100000;
    // 线程数
    static final int threadLenght = 1000;


    public static void main(String[] args) throws InterruptedException {

        Thread[] t1 = new Thread[threadLenght];
        Object lock = new Object();
        for (int i = 0; i <t1.length; i++) {
            t1[i] = new Thread(()->{
                for (int k = 0; k < len ; k++) {
                    synchronized(lock){
                            count1++;
                    }
                }
            });
        }
        long time = GetRunTime(t1);
        System.out.println("sync: " + count1 +" ，time: "+ time);

        // AtomicLong
        Thread[] t2 = new Thread[threadLenght];
        for (int i = 0; i < t2.length; i++) {
            t2[i] = new Thread(()->{
                for (int k = 0; k < len; k++) {
                    count2.incrementAndGet();
                }
            });
        }
        time = GetRunTime(t2);
        System.out.println("atomic: " + count2 +" ，time:"+ time);

        // LongAdder
        Thread[] t3 = new Thread[threadLenght];
        for (int i = 0; i < t3.length; i++) {
            t3[i] = new Thread(()->{
                for (int k = 0; k < len; k++) {
                    count3.increment();
                }
            });
        }
        time = GetRunTime(t3);
        System.out.println("LongAdder: " + count3 +" ，time:"+ time);

    }

    public static Long GetRunTime(Thread[] ths) throws InterruptedException {

        long start = System.currentTimeMillis();
        for (Thread t : ths) t.start();
        for (Thread t : ths) t.join();
        long end = System.currentTimeMillis();
        return end - start;
    }
}
